# pur @ 统一的makefile，适用于编译cpp和c程序或者混合cpp和c的程序，只能生成程序或so
# date @ 2014.02.08
# author @ haibin.wang
#
#使用方法
# 此makefile文件会编译当前目录和子目录下的所有cpp文件和c文件，生成.o文件，并最终生成TARGET目标
# 1、生成so文件直接将TARGET后的test修改为xxx.so，生成so文件会影响程序CFLAGS参数
# 2、生成引用其他库，可以修改变量LIBPATH和INCLUDEPATH后的相关内容
# 
# 缺点，
# 1、目前无法在一个makefile中同时生成多个程序或库文件
# 2、编译后的库可优化为是否使用相对路径 -Wlpath -rpath
# 3、无法生成.a文件,由于.o需要先生成相关的.a文件，而.a文件不存在
# 4、子目录中没有makefile文件会报错
#


TARGET := test
LIBPATH := 
INCLUDEPATH := 

OBJS := $(patsubst %.c,%.o, $(wildcard *.c)) $(patsubst %.cpp,%.o, $(wildcard *.cpp)) #将当前目录下所有为.cpp和.c的文件的名称，并将临时名称的.cpp和.c替换为.o
CFLAGS := -g
SUBDIRS := `ls -F | grep /` #获取当前目录下的目录名

#判定是否在生成对象中有so，如果有so则修改CFLAGS为-g -fPIC -shared,ifeq后必须有空格
ifeq ($(findstring .so, $(TARGET)), .so) 
	CFLAGS := -g -fPIC -shared
endif

.PHONY = help all clean #phony关键字，避免和同名文件冲突和改善心能

all:$(TARGET)
help:
	@(echo "usage: make help|all|clean")  #@放在命令前面隐藏命令输出
	@(echo $(OBJS))
	@echo $(SRCS) #输出变量值

#编译.c和.cpp文件为.o文件
%.o:%.c
	@(echo 'building $<'; $(CXX) $(CFLAGS) $(INCLUDEPATH) $(LIBPATH) -c $< ) #C 为宏定义变量，为C++编译器的名称，默认为g++
%.o:%.cpp
	@(echo 'building $<'; $(CXX) $(CFLAGS) $(INCLUDEPATH) $(LIBPATH) -c $< ) #CXX 为宏定义变量，为C++编译器的名称，默认为g++

#遍历SUBDIRS中的所有目录, #make -C进入到dir目录中
#将.o文件编译为target对象
$(TARGET):$(OBJS)
	@for dir in $(SUBDIRS); do \
	make -C $$dir all || exit 1; \
	done
ifeq ($(findstring .a, $(TARGET)), .a) 
	ar -rc $@ $(OBJS) 
#.o文件编译为target对象
else
	$(CXX) $(CFLAGS) $(INCLUDEPATH) $(LIBPATH) -o $@ $^
endif
	rm -rf *.o

clean:
	rm -rf $(TARGET) *.o
	@for dir in $(SUBDIRS); do \
	make -C $$dir clean || exit 1; \
	done
